www.gusucode.com > Piwik 网站流量统计系统 v2.9.1PHP源码程序 > Piwik 网站流量统计系统 v2.9.1/piwik/piwik/core/DataAccess/ArchiveInvalidator.php

    <?php
/**
 * Piwik - free/libre analytics platform
 *
 * @link http://piwik.org
 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 *
 */

namespace Piwik\DataAccess;


use Piwik\Date;
use Piwik\Db;
use Piwik\Plugins\PrivacyManager\PrivacyManager;
use Piwik\Period;
use Piwik\Period\Week;

/**
 * Marks archives as Invalidated by setting the done flag to a special value (see Model->updateArchiveAsInvalidated)
 *
 * Invalidated archives can still be selected and displayed in UI and API (until they are reprocessed by core:archive)
 *
 * The invalidated archives will be deleted by ArchivePurger
 *
 * @package Piwik\DataAccess
 */
class ArchiveInvalidator {

    private $warningDates = array();
    private $processedDates = array();
    private $minimumDateWithLogs = false;
    private $invalidDates = array();

    /**
     * @param $idSites array
     * @param $dates string
     * @param $period string
     * @return array
     * @throws \Exception
     */
    public function markArchivesAsInvalidated(array $idSites, $dates, $period)
    {
        $this->findOlderDateWithLogs();
        $datesToInvalidate = $this->getDatesToInvalidateFromString($dates);
        $minDate = $this->getMinimumDateToInvalidate($datesToInvalidate);

        \Piwik\Plugins\SitesManager\API::getInstance()->updateSiteCreatedTime($idSites, $minDate);

        $datesByMonth = $this->getDatesByYearMonth($datesToInvalidate);
        $this->markArchivesInvalidatedFor($idSites, $period, $datesByMonth);

        $this->persistInvalidatedArchives($idSites, $datesByMonth);

        return $this->makeOutputLogs();
    }

    /**
     * @param $toInvalidate
     * @return bool|Date
     * @throws \Exception
     */
    private function getMinimumDateToInvalidate($toInvalidate)
    {
        /* @var $date Date */
        $minDate = false;
        foreach ($toInvalidate as $date) {
            // Keep track of the minimum date for each website
            if ($minDate === false
                || $date->isEarlier($minDate)
            ) {
                $minDate = $date;
            }
        }
        if (empty($minDate)) {
            throw new \Exception("Check the 'dates' parameter is a valid date.");
        }
        return $minDate;
    }

    /**
     * @param $idSites
     * @param $period string
     * @param $datesByMonth array
     * @throws \Exception
     */
    private function markArchivesInvalidatedFor($idSites, $period, $datesByMonth)
    {
        $invalidateForPeriodId = $this->getPeriodId($period);

        // In each table, invalidate day/week/month/year containing this date
        $archiveTables = ArchiveTableCreator::getTablesArchivesInstalled();
        foreach ($archiveTables as $table) {
            // Extract Y_m from table name
            $suffix = ArchiveTableCreator::getDateFromTableName($table);
            if (!isset($datesByMonth[$suffix])) {
                continue;
            }
            // Dates which are to be deleted from this table
            $datesToDelete = $datesByMonth[$suffix];
            self::getModel()->updateArchiveAsInvalidated($table, $idSites, $invalidateForPeriodId, $datesToDelete);
        }
    }

    /**
     * Ensure the specified dates are valid.
     * Store invalid date so we can log them
     * @param $dates string
     * @return Date[]
     */
    private function getDatesToInvalidateFromString($dates)
    {
        $toInvalidate = array();

        $dates = explode(',', trim($dates));
        $dates = array_unique($dates);

        foreach ($dates as $theDate) {
            $theDate = trim($theDate);
            try {
                $date = Date::factory($theDate);
            } catch (\Exception $e) {
                $this->invalidDates[] = $theDate;
                continue;
            }
            if ($date->toString() == $theDate) {
                $toInvalidate[] = $date;
            } else {
                $this->invalidDates[] = $theDate;
            }
        }
        return $toInvalidate;
    }

    private function findOlderDateWithLogs()
    {
        // If using the feature "Delete logs older than N days"...
        $purgeDataSettings = PrivacyManager::getPurgeDataSettings();
        $logsAreDeletedBeforeThisDate = $purgeDataSettings['delete_logs_schedule_lowest_interval'];
        $logsDeleteEnabled = $purgeDataSettings['delete_logs_enable'];

        if ($logsDeleteEnabled
            && $logsAreDeletedBeforeThisDate
        ) {
            $this->minimumDateWithLogs = Date::factory('today')->subDay($logsAreDeletedBeforeThisDate);
        }
    }

    /**
     * Given the list of dates, process which tables YYYY_MM we should delete from
     *
     * @param $datesToInvalidate Date[]
     * @return array
     */
    private function getDatesByYearMonth($datesToInvalidate)
    {
        $datesByMonth = array();
        foreach ($datesToInvalidate as $date) {
            // we should only delete reports for dates that are more recent than N days
            if ($this->minimumDateWithLogs
                && $date->isEarlier($this->minimumDateWithLogs)
            ) {
                $this->warningDates[] = $date->toString();
                continue;
            }

            $this->processedDates[] = $date->toString();

            $month = $date->toString('Y_m');
            // For a given date, we must invalidate in the monthly archive table
            $datesByMonth[$month][] = $date->toString();

            // But also the year stored in January
            $year = $date->toString('Y_01');
            $datesByMonth[$year][] = $date->toString();

            // but also weeks overlapping several months stored in the month where the week is starting
            /* @var $week Week */
            $week = Period\Factory::build('week', $date);
            $weekAsString = $week->getDateStart()->toString('Y_m');
            $datesByMonth[$weekAsString][] = $date->toString();

        }
        return $datesByMonth;
    }

    /**
     * @return array
     */
    private function makeOutputLogs()
    {
        $output = array();
        if ($this->warningDates) {
            $output[] = 'Warning: the following Dates have not been invalidated, because they are earlier than your Log Deletion limit: ' .
                implode(", ", $this->warningDates) .
                "\n The last day with logs is " . $this->minimumDateWithLogs . ". " .
                "\n Please disable 'Delete old Logs' or set it to a higher deletion threshold (eg. 180 days or 365 years).'.";
        }
        if ($this->invalidDates) {
            $output[] = 'Warning: some of the Dates to invalidate were invalid: ' .
                implode(", ", $this->invalidDates) . ". Piwik simply ignored those and proceeded with the others.";
        }

        $output[] = "Success. The following dates were invalidated successfully: " . implode(", ", $this->processedDates);
        return $output;
    }

    /**
     * @param $period
     * @return bool|int
     */
    private function getPeriodId($period)
    {
        if (!empty($period)) {
            $period = Period\Factory::build($period, Date::today());
        }
        $invalidateForPeriod = $period ? $period->getId() : false;
        return $invalidateForPeriod;
    }

    /**
     * @param array $idSites
     * @param $datesByMonth
     */
    private function persistInvalidatedArchives(array $idSites, $datesByMonth)
    {
        $yearMonths = array_keys($datesByMonth);
        $yearMonths = array_unique($yearMonths);

        $store = new InvalidatedReports();
        $store->addInvalidatedSitesToReprocess($idSites);
        $store->addSitesToPurgeForYearMonths($idSites, $yearMonths);
    }

    private static function getModel()
    {
        return new Model();
    }

}